﻿using GomokuAI;
using GomokuCore;
using Infrastructure.UI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.System.Threading;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

namespace Gomoku
{
    public sealed partial class PlayPage : Gomoku.Common.LayoutAwarePage
    {
        Game game;
        bool initialized;

        public PlayPage()
        {
            this.InitializeComponent();

            this.EnablePrivacyPolicy(PrivacyPolicy.RunXiaDianQi);
        }

        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            InitGame((GameMode)navigationParameter);
        }

        protected override void SaveState(Dictionary<String, Object> pageState)
        {
        }

        private void InitGame(GameMode mode)
        {
            if (!initialized)
            {
                for (int row = 0; row < Game.BoardSize; row++)
                {
                    boardGrid.RowDefinitions.Add(new RowDefinition());
                }

                for (int col = 0; col < Game.BoardSize; col++)
                {
                    boardGrid.ColumnDefinitions.Add(new ColumnDefinition());
                }

                for (int row = 0; row < Game.BoardSize; row++)
                {
                    for (int col = 0; col < Game.BoardSize; col++)
                    {
                        string imageFileName = string.Format("ms-appx:///Skin/Classic/{0}{1}{2}{3}node.png",
                            row == 0 ? "north" : string.Empty,
                            row == Game.BoardSize - 1 ? "south" : string.Empty,
                            col == 0 ? "west" : string.Empty,
                            col == Game.BoardSize - 1 ? "east" : string.Empty);

                        var grid = new Grid();
                        grid.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri(imageFileName)) };
                        grid.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Stretch;
                        grid.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Stretch;
                        Grid.SetRow(grid, row);
                        Grid.SetColumn(grid, col);
                        grid.Tag = "Board";
                        boardGrid.Children.Add(grid);
                    }
                }

                initialized = true;
            }
            else
            {
                var stones = boardGrid.Children.Where(grid => ((Grid)grid).Tag == "Stone").ToArray();
                foreach (var stone in stones)
                {
                    boardGrid.Children.Remove(stone);
                }
            }

            Player blackPlayer = null;
            Player whitePlayer = null;

            if (mode == GameMode.MultiPlayer)
            {
                blackPlayer = new HumanPlayer { Name = "Player1", Color = PositionStatus.Black };
                whitePlayer = new HumanPlayer { Name = "Player2", Color = PositionStatus.White };
            }
            else if (mode == GameMode.SinglePlayer)
            {
                blackPlayer = new HumanPlayer { Name = "You", Color = PositionStatus.Black };
                whitePlayer = new ComputerPlayer { Name = "Computer", Color = PositionStatus.White };
            }

            game = new Game(mode, blackPlayer, whitePlayer);

            blackPlayerTextBlock.Text = game.BlackPlayer.Name;
            whitePlayerTextBlock.Text = game.WhitePlayer.Name;

            blackStoneImage.Visibility = Visibility.Visible;
            whiteStoneImage.Visibility = Visibility.Collapsed;
        }

        private bool isBusy;

        private void boardGrid_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            if (isBusy)
                return;

            isBusy = true;

            var cellSize = boardGrid.Height / Game.BoardSize;

            var pos = e.GetCurrentPoint((UIElement)sender).Position;

            int row = (int)(pos.Y / cellSize);
            int col = (int)(pos.X / cellSize);

            if (game.Board[row, col] != PositionStatus.Empty)
            {
                isBusy = false;
                return;
            }

            PutStone(new Position(row, col));
            var gameEnd = GetVictoryStatus();

            if (!gameEnd && game.Mode == GameMode.SinglePlayer)
            {
                ComputerPutStoneAsync();
            }
            else
            {
                isBusy = false;
            }
        }

        private Task ComputerPutStoneAsync()
        {
            return Task.Run(() =>
                {
                    var computerPos = game.WhitePlayer.Think(game.Board);
                    Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            PutStone(computerPos);
                            GetVictoryStatus();
                            isBusy = false;
                        });
                });
        }

        private void PutStone(Position pos)
        {
            var color = game.CurrentPlayer.Color;

            string imageFileName = string.Format("ms-appx:///Skin/Classic/{0}stone.png",
                color == PositionStatus.Black ? "black" : "white");

            game.Move(pos);

            var grid = new Grid();
            grid.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri(imageFileName)) };
            grid.Width = 30;
            grid.Height = 30;
            Grid.SetRow(grid, pos.Row);
            Grid.SetColumn(grid, pos.Col);
            grid.Tag = "Stone";
            boardGrid.Children.Add(grid);

            blackStoneImage.Visibility = color == PositionStatus.Black ? Visibility.Collapsed : Visibility.Visible;
            whiteStoneImage.Visibility = color == PositionStatus.White ? Visibility.Collapsed : Visibility.Visible;
        }

        private bool GetVictoryStatus()
        {
            string msg;
            var status = game.GetVictoryStatus();

            if (status == GameStatus.InProgress)
                return false;

            if (status == GameStatus.BlackWin)
            {
                msg = "Black Win!";
            }
            else if (status == GameStatus.WhiteWin)
            {
                msg = "White Win!";
            }
            else
            {
                msg = "Draw!";
            }

            MessageBox.Show(msg);

            InitGame(game.Mode);

            return true;
        }

        private void backButton_Click(object sender, RoutedEventArgs e)
        {
            Frame.Navigate(typeof(MainPage));
        }

        private void restartButton_Click(object sender, RoutedEventArgs e)
        {
            InitGame(game.Mode);
        }
    }
}
